<?
//Check for PDO, if not exist then use old method
	include_once(dirname(__FILE__) . "/db_config.inc.php");

	class database{
		function database($db = ""){
			$this->break_on_err = BREAK_ON_ERR;

			$this->table = array();
			$this->server = DB_SERVER;
			$this->db = ($db == "") ? DEFAULT_DB : $db;
			$this->error = false;
			$this->dbType = "";

			if(preg_match("/(\.sqlite)|(\.rdb)/", $this->db)){
				$this->dbType = "sqlite";
				try
				{
					$this->pdo = new PDO("sqlite:" . $this->db);
					$row = $this->query("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name");
					foreach($row as $r){
						$this->table[] = $r['name'];
					}
				}
				catch(PDOException $e)
				{
					$this->error = $e->getMessage();
					$this->output_error();
				}
			} else {
				$this->dbType = "mysql";
				if(stristr($this->server, ":")){
					list($host, $port) = explode(":", $this->server);
					try{
						$this->pdo = new PDO("mysql:dbname=" . $this->db . ";host=" . $host . ";port=" . $port, DB_USER, DB_PASS);
					} catch(PDOException $e) {
						$this->error = $e->getMessage();
						$this->output_error();
					}
				} else {
					try{
						$this->pdo = new PDO("mysql:dbname=" . $this->db . ";host=" . $this->server, DB_USER, DB_PASS);
					} catch(PDOException $e){
						$this->error = $e->getMessage();
						$this->output_error();
					}
				}

				$this->query("SHOW TABLES FROM " . $this->db);
				foreach($this->row as $r){
					foreach($r as $tn){
						$this->table[] = $tn;
					}
				}
			}

			$this->num_rows = -1;
			$this->row = array();
			$this->results = array();
		}

		function listFields($tableName) {
			$fld = array();

			if($this->dbType == "sqlite"){
				$row = $this->query("PRAGMA table_info('" . $tableName . "')");
				foreach($row as $r){
					$fld[] = $r['name'];
				}
			}

			if($this->dbType == "mysql"){
				$this->query("show columns from " . $tableName);

				foreach($this->row as $r){
					$fld[] = $r["Field"];
				}
			}

			Return $fld;
		}

		function set_db($db_name){
			$this->db = $db_name;
		}

		function execute($sqlPrep, $valList = null, $print_sql = false){
			unset($this->row);
			$this->num_rows = -1;

			$this->sql = $sqlPrep;
			$this->valList = $valList;

/*
			$sqlp = SqlParser::ParseString($sqlPrep);
			 $sqlq = $sqlp->query;

			//debug echo "<pre>"; print_r( $sqlq); echo "</pre>";if (is_array($sqlq)) echo "ok";



			if(!isset($sqlq['where']) && key_exists("update", $sqlq)){
				$this->error = "There is no 'where' clause in the provided SQL.";
				$this->output_error();
			}
*/

			try{
				$prep = $this->pdo->prepare($sqlPrep);
			} catch(PDOException $e) {
				$this->error = $e->getMessage();
				$this->output_error();
			}

			if(!$prep){
				$this->error = "Unable to prepare PDO.";
				$this->output_error();
			}

			try{
				$prep->execute($valList);
			} catch(PDOException $e) {
				$this->error = $e->getMessage();
				$this->output_error();
			}

			preg_match("/insert into ([^\s]+)/i", $sqlPrep, $iFound);
			if(count($iFound) > 0){
				$tblName = $iFound[1];
				try{
				//Get field list & look for autoinc field
					$idField = "";
					switch($this->dbType){
						case "sqlite":
							$row = $this->query("PRAGMA table_info('" . $tblName . "')");
							foreach($row as $r){
								if(strtolower($r['type']) == "integer" && $r['pk'] == 1){
									$idField = $r['name'];
									break;
								}
							}
							break;

						case "mysql":
							$row = $this->query("DESCRIBE " . $tblName);
							foreach($row as $r){
								if($r['Extra'] == "auto_increment"){
									$idField = $r['Field'];
									break;
								}
							}
							break;
					}

					if($idField != ""){
						try{
							$this->insert_id = $this->pdo->lastInsertId("id");
						} catch(PDOException $e) {
							$this->error = $e->getMessage();
							$this->output_error();
						}
					} else {
						$this->insert_id = "Unknown";
					}
				} catch(PDOException $e) {
					$this->error = $e->getMessage();
					$this->output_error();
				}
			}
		}

		function query($sqlPrep, $valList = null, $print_sql = false){
			$this->row = array();
			try{
				$prep = $this->pdo->prepare($sqlPrep);
			} catch(PDOException $e) {
				$this->error = $e->getMessage();
				$this->output_error();
			}

			try{
				$prep->execute($valList);
			} catch(PDOException $e) {
				$this->error = $e->getMessage();
				$this->output_error();
			}

			try{
				$this->results = $prep->fetchAll();
			} catch(PDOException $e) {
				$this->error = $e->getMessage();
				$this->output_error();
			}

			if(count($this->results)){
				foreach($this->results as $rc=>$r){
					$this->row[$rc] = array();
					foreach($r as $k=>$v){
						if(!is_numeric($k)){
							$this->row[$rc][$k] = $v;
						}
					}
				}
			}

			$this->num_rows = count($this->row);
			return $this->row;
		}

		function output_error(){
			if(!$this->break_on_err || !$this->error) return false;
			die("\n\nError: " . $this->error . "\n\n=======\n\n" . $this->sql . "\n\n" . print_r($this->valList, true)) . "\n\n";
		}

		function arrayUpdate($data, $table, $wherePrep, $whereValList){
/*
	$data = array where key = column name & value = assigned value for column
	$table = table name to update
	$wherePrep = a where clause (without the WHERE keyword) with "?" in place of actual values
	$whereValList = array of values that correspond to the "?" in $wherePrep
*/
			$validField = $this->listFields($table);

			$sql = "UPDATE " . $table . " SET ";
			$sqlFld = $sqlFldVal = array();
			foreach($data as $k=>$v){
				if(in_array($k, $validField) && $v != ""){
					$sqlFld[] = "`" . $k . "` = ?";
					$sqlFldVal[] = $v;
				}
			}

			$sql .= implode(",", $sqlFld) . " WHERE " . $wherePrep;

			$this->sql = $sql;
			$this->sqlVal = $sqlFldVal;

			$this->execute($sql, array_merge($sqlFldVal, $whereValList));

			$this->output_error();
		}

		function arrayInsert($data, $table){
/*
	$data = array where key = column name & value = assigned value for column
	$table = table name to update
*/
			$validField = $this->listFields($table);

			$writeData = array();
			$fldName = array();
			$dataVal = array();
			foreach($data as $k=>$v){
				if(in_array($k, $validField) && $v != ""){
					$fldName[] = "`" . $k . "`";
					$writeData[$k] = "?";
					$dataVal[] = $v;
				}
			}

			$sql = "INSERT INTO " . $table . " (" . implode(",", $fldName) . ") VALUES (" . implode(",", $writeData) . ")";

			$this->execute($sql, $dataVal);

			$this->output_error();
		}

		function safe($v){
			$link = mysql_connect($this->server, DB_USER, DB_PASS);
			mysql_select_db($this->db);

			return mysql_real_escape_string($v, $link);
		}

		function buildIV($seed){
			$iv = trim($seed);
			$i=0;
			while(strlen($iv) < 16){
				$iv .= bin2hex($i);
				$i++;
			}

			return substr($iv, 0, 16);
		}

		function buildKey($seed){
			$key = trim($seed);
			$i=0;
			while(strlen($key) < 32){
				$key .= bin2hex($i);
				$i++;
			}

			return substr($key, 0, 32);
		}

		function aesEncrypt($cleartext, $ivSeed, $keySeed){
			//ivSeed & keySeed can be strings of any length - the buildIV & buildKey functions will adjust them accordingly

			$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');


			$iv_size = mcrypt_enc_get_iv_size($cipher);

			$iv = $this->buildIV($ivSeed);
			$key256 = $this->buildKey($keySeed);

			if (mcrypt_generic_init($cipher, $key256, $iv) != -1)
			{
				// PHP pads with NULL bytes if $cleartext is not a multiple of the block size..
				$cipherText = mcrypt_generic($cipher,$cleartext );
				mcrypt_generic_deinit($cipher);
			}

			return bin2hex($cipherText);
		}

	}








/**
 * This is a simple sql tokenizer / parser.
 * I needed code to get the total count of a paged recordset, so I wrote this.
 * It seems to handle sane mssql/mysql queries.
 *
 * PROTOTYPE
 *
 * @author Justin Carlson <justin.carlson@gmail.com>
 * @license LGPL
 * @version 0.0.3
 */


class SqlParser {

    var $handle = null;
    public static $querysections = array('alter', 'create', 'drop', 'select', 'delete', 'insert', 'update','from','where','limit','order','group');
    public static $operators = array('=', '<>', '<', '<=', '>', '>=', 'like', 'clike', 'slike', 'not', 'is', 'in', 'between');
    public static $types = array('character', 'char', 'varchar', 'nchar', 'bit', 'numeric', 'decimal', 'dec', 'integer', 'int', 'smallint', 'float', 'real', 'double', 'date', 'datetime', 'time', 'timestamp', 'interval', 'bool', 'boolean', 'set', 'enum', 'text');
    public static $conjuctions = array('by', 'as', 'on', 'into', 'from', 'where', 'with');
    public static $funcitons = array('avg', 'count', 'max', 'min', 'sum', 'nextval', 'currval', 'concat');
    public static $reserved = array('absolute', 'action', 'add', 'all', 'allocate', 'and', 'any', 'are', 'asc', 'ascending', 'assertion', 'at', 'authorization', 'begin', 'bit_length', 'both', 'cascade', 'cascaded', 'case', 'cast', 'catalog', 'char_length', 'character_length', 'check', 'close', 'coalesce', 'collate', 'collation', 'column', 'commit', 'connect', 'connection', 'constraint', 'constraints', 'continue', 'convert', 'corresponding', 'cross', 'current', 'current_date', 'current_time', 'current_timestamp', 'current_user', 'cursor', 'day', 'deallocate', 'declare', 'default', 'deferrable', 'deferred', 'desc', 'descending', 'describe', 'descriptor', 'diagnostics', 'disconnect', 'distinct', 'domain', 'else', 'end', 'end-exec', 'escape', 'except', 'exception', 'exec', 'execute', 'exists', 'external', 'extract', 'false', 'fetch', 'first', 'for', 'foreign', 'found', 'full', 'get', 'global', 'go', 'goto', 'grant', 'group', 'having', 'hour', 'identity', 'immediate', 'indicator', 'initially', 'inner', 'input', 'insensitive', 'intersect', 'isolation', 'join', 'key', 'language', 'last', 'leading', 'left', 'level', 'limit', 'local', 'lower', 'match', 'minute', 'module', 'month', 'names', 'national', 'natural', 'next', 'no', 'null', 'nullif', 'octet_length', 'of', 'only', 'open', 'option', 'or', 'order', 'outer', 'output', 'overlaps', 'pad', 'partial', 'position', 'precision', 'prepare', 'preserve', 'primary', 'prior', 'privileges', 'procedure', 'public', 'read', 'references', 'relative', 'restrict', 'revoke', 'right', 'rollback', 'rows', 'schema', 'scroll', 'second', 'section', 'session', 'session_user', 'size', 'some', 'space', 'sql', 'sqlcode', 'sqlerror', 'sqlstate', 'substring', 'system_user', 'table', 'temporary', 'then', 'timezone_hour', 'timezone_minute', 'to', 'trailing', 'transaction', 'translate', 'translation', 'trim', 'true', 'union', 'unique', 'unknown', 'upper', 'usage', 'user', 'using', 'value', 'values', 'varying', 'view', 'when', 'whenever', 'work', 'write', 'year', 'zone', 'eoc');
    public static $startparens = array('{', '(');
    public static $endparens = array('}', ')');
    public static $tokens = array(',', ' ');
    public $query = '';
    public function __construct() { }

    /**
     * Simple SQL Tokenizer
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license GPL
     * @param string $sqlQuery
     * @return token array
     */
    public static function Tokenize($sqlQuery,$cleanWhitespace = true) {

        /**
         * Strip extra whitespace from the query
         */
        if($cleanWhitespace) {
         $sqlQuery = ltrim(preg_replace('/[\\s]{2,}/',' ',$sqlQuery));
        }

        /**
         * Regular expression based on SQL::Tokenizer's Tokenizer.pm by Igor Sutton Lopes
         **/
        $regex = '('; # begin group
        $regex .= '(?:--|\\#)[\\ \\t\\S]*'; # inline comments
        $regex .= '|(?:<>|<=>|>=|<=|==|=|!=|!|<<|>>|<|>|\\|\\||\\||&&|&|-|\\+|\\*(?!\/)|\/(?!\\*)|\\%|~|\\^|\\?)'; # logical operators
        $regex .= '|[\\[\\]\\(\\),;`]|\\\'\\\'(?!\\\')|\\"\\"(?!\\"")'; # empty single/double quotes
        $regex .= '|".*?(?:(?:""){1,}"|(?<!["\\\\])"(?!")|\\\\"{2})|\'.*?(?:(?:\'\'){1,}\'|(?<![\'\\\\])\'(?!\')|\\\\\'{2})'; # quoted strings
        $regex .= '|\/\\*[\\ \\t\\n\\S]*?\\*\/'; # c style comments
        $regex .= '|(?:[\\w:@]+(?:\\.(?:\\w+|\\*)?)*)'; # words, placeholders, database.table.column strings
        $regex .= '|[\t\ ]+';
        $regex .= '|[\.]'; #period

        $regex .= ')'; # end group

        // get global match
        preg_match_all( '/' . $regex . '/smx', $sqlQuery, $result );

        // return tokens
        return $result[0];

    }

    /**
     * Simple SQL Parser
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @param string $sqlQuery
     * @param bool optional $cleanup
     * @return SqlParser Object
     */
    public static function ParseString($sqlQuery) {
ob_start();
        // returns a SqlParser object
        if (! isset( $this )) {
            $handle = new SqlParser();
        } else {
            $handle = $this;
        }

        // copy and cut the query
        $tokens = self::Tokenize( $sqlQuery );
        $tokenCount = count( $tokens );
        $queryParts = array();
        $section = $tokens[0];

        // parse the tokens
        for ($t = 0; $t < $tokenCount; $t ++) {
            if (in_array( $tokens[$t], self::$startparens )) {

                $sub = $handle->readsub( $tokens, $t );
                $handle->query[$section].= $sub;

            } else {

                if(in_array(strtolower($tokens[$t]),self::$querysections) && !isset($handle->query[$tokens[$t]])) {
                    $section = strtolower($tokens[$t]);
                }

                // rebuild the query in sections
                if (!isset($handle->query[$section])) $handle->query[$section] = '';
                $handle->query[$section] .= $tokens[$t];

            }

        }
ob_clean();
        return $handle;

    }

     /**
     * Parses a section of a query ( usually a sub-query or where clause )
     *
     * @param array $tokens
     * @param int $position
     * @return string section
     */
    private function readsub($tokens, &$position) {

        $sub = $tokens[$position];
        $tokenCount = count( $tokens );
        $position ++;
        while ( ! in_array( $tokens[$position], self::$endparens ) && $position < $tokenCount ) {

            if (in_array( $tokens[$position], self::$startparens )) {
                $sub.= $this->readsub( $tokens, $position );
                $subs++;
            } else {
                $sub.= $tokens[$position];
            }
            $position ++;
        }
        $sub.= $tokens[$position];
        return $sub;
    }


    /**
     * Returns manipulated sql to get the number of rows in the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getCountQuery() {

        $this->query['select'] = 'select count(*) as `count` ';
        unset($this->query['limit']);
        #die(implode('',$this->query));
        return implode('',$this->query);

    }

    /**
     * Returns manipulated sql to get the unlimited number of rows in the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getLimitedCountQuery() {

        $this->query['select'] = 'select count(*) as `count` ';
        return implode('',$this->query);

    }

    /**
     * Returns the select section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getSelectStatement() {

        return $this->query['select'];

    }

    /**
     * Returns the from section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getFromStatement() {

        return $this->query['from'];

    }

    /**
     * Returns the where section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getWhereStatement() {

        return $this->query['where'];

    }

    /**
     * Returns the limit section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getLimitStatement() {

        return $this->query['limit'];

    }

    /**
     * Returns the where section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function get($which) {

        if(!isset($this->query[$which])) return false;
        return $this->query[$which];

    }

    /**
     * Returns the where section of the query.
     *
     * @author Justin Carlson <justin.carlson@gmail.com>
     * @license LGPL
     * @return string sql
     */
    public function getArray( ) {

        return $this->query;

    }
}

?>